package capaDominio;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.SocketTimeoutException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import org.jdom.Document;
import org.jdom.Element;

import capaDatos.BaseDatos;
import capaDatos.User;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Tomas / AJ
 */

class ConexionUsuario extends Thread {
    private String usuario = "@desconocido";
    private String userIP = "";
	private static final String secreto = "$€<R3t0_w01ón";
    BufferedReader entrada = null;
	PrintWriter salida = null;
	Socket socket;
	Boolean finish = false;
    Map<String, User> usuarios; // TODO sera base de datos
    

    static ArrayList<String> errores;

    ConexionUsuario(Socket client) {
        this.socket = client;
        this.userIP = client.getInetAddress().toString().replace("/", "");
        this.usuarios = new HashMap<String, User>();        
        try{
			this.entrada = utilsIO.getBufferedReader(this.socket);
			this.salida = utilsIO.getPrintWriter(this.socket);
	    }
		catch(Exception e){
			if (socket.isClosed()) System.out.println("Socket cerrado");
			else e.printStackTrace();
		}
        
        errores = new ArrayList<String>();
		errores.add("Lista de errores");					// 0
		errores.add("Usuario o contraseña incorrectos");	// 1
		errores.add("XML incorrecto");						// 2
		errores.add("Usuario ya registrado");    			// 3
		errores.add("Error al addContacto");				// 4
		errores.add("Error al addItinerario");				// 5
		errores.add("Error al getItinerario");				// 6
		errores.add("Error al addProducto");				// 7
		errores.add("Error al addImage");					// 8
    }

    @Override
    public void run(){
		while (true) {
			String msj = null;
			try {
				msj = entrada.readLine();
				System.out.println("ConexionUsuario.java_run"+": "+msj);
			}
			catch(SocketTimeoutException s) {
				System.out.println("ConexionUsuario.run : TimeOut en la lectura del socket "+this.socket+"!");
			}
			catch(IOException e) {
				System.out.println("ConexionUsuario.run : Error al intentar leer el socket "+this.socket);
				System.out.println("ConexionUsuario.run : Conexion cerrada desde el usuario");
			}
			
			if (msj == null) {
				System.out.println("ConexionUsuario.run : El mensaje es nulo. Salimos del bucle");
				break;
			}

			Document xml = utilsXML.getXML(msj);
				
            if (xml == null) { 					// Si es incorrecto, ignoramos el mensaje.
				salida.println(SP_XMLs.XML_errorConexion(2, errores.get(2)));
				continue;
			}

            if (utilsXML.getXML_type(xml).equals("login")) {
				int error = loginCorrecto(xml);
				String userStatus = getStatusUser();
				if (error == 0) {
					String xml1 = SP_XMLs.XML_resLogin(usuario, userStatus, userIP, secreto);
					System.out.println("ConexionUsuario.run: "+xml1.replace("> ", "\r\n"));
					salida.println(xml1);
					System.out.println("ConexionUsuario.run : Login con " +usuario+ " correcto. ");
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
            
            if (utilsXML.getXML_type(xml).equals("registro")) {
				int error = registroCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resRegistro());
					System.out.println("ConexionUsuario.run: Login con " +usuario+ " correcto. ");
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
            
            if (utilsXML.getXML_type(xml).equals("addContacto")) {
				int error = addContactoCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resAddContacto());
					System.out.println("ConexionUsuario.run: Login con " +usuario+ " correcto. ");
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("addItinerario")) {
				int error = addItinerarioCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resOperacion());
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("getItinerario")) {
				int error = 0;
				String result = getItinerarioCorrecto(xml);
				System.out.println("getItinerario");
				if (error == 0) {
					salida.println(SP_XMLs.XML_resItinerario(result));
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("addProductos")) {
				int error = addProductoCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resOperacion());
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			

			if (utilsXML.getXML_type(xml).equals("addCheckpoint")) {
				int error = addCheckpointCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resOperacion());
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("listarProductos")) {
				int error = 0;
				ResultSet result = listarProductosCorrectos();
				if (error == 0) {
					salida.println(SP_XMLs.XML_resListarProductos(result));
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("listarCheckpoints")) {
				int error = 0;
				ResultSet result = listarCheckpointsCorrectos(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resListarCheckpoints(result));
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("getImage")) {
				int error = 0;
				String result = getImageCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resImage(result));
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("addImage")) {
				int error = addImageCorrecto(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resOperacion());
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
			
			if (utilsXML.getXML_type(xml).equals("listarContactos")) {
				int error = 0;
				ResultSet result = listarContactosCorrectos(xml);
				if (error == 0) {
					salida.println(SP_XMLs.XML_resListarContactos(result));
				}
				else salida.println(SP_XMLs.XML_errorConexion(error, errores.get(error)));
			}
            
		}
		
		try {
			this.socket.close();
		}
		catch (IOException e) {
			System.out.println("ConexionUsuario.run: Error al intentar cerrar el socket!");
			e.printStackTrace();
		}
		System.out.println("ConexionUsuario.run : Conexion cerrada. Este Thread se cerrara.");
	}

    private int loginCorrecto(Document xml) {
        Element mensaje = xml.getRootElement();
        Element chat = mensaje.getChild("login");

        // Token incorrecto
        usuario = chat.getAttributeValue("username");
        String password = chat.getAttributeValue("password");
		try {
			ResultSet rs = BaseDatos.getUser(usuario, password);
			if (!rs.next()) return 1;
			rs.close();
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        }
        return 0;
	}
    
    private String getStatusUser() {
    	String res = "user";
    	try {
	    	if(this.usuario.equals("@desconocido")) {
	    		throw new Exception("Intento de obtener el estado del usuario sin tener el usuario definido!");
	    	}
		
			ResultSet rs = BaseDatos.getStatusUser(this.usuario);
			if (!rs.next()) {
				throw new Exception("No existe el usuario ");
			}
			
			res = rs.getString("status");
			
			rs.close();
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        } catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
        return res;
    }
    
    private int registroCorrecto(Document xml) {
        Element mensaje = xml.getRootElement();
        Element chat = mensaje.getChild("registro");

        usuario = chat.getAttributeValue("username");
        String password = chat.getAttributeValue("password");
		try {
			ResultSet rs = BaseDatos.getUser(usuario);
			if (rs.next()){
				rs.close();
				return 3;
			}
			BaseDatos.insertarUsuario(usuario, password,"user");
			rs.close();
			return 0;
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        }
		return 0;
	}
    
    private int addContactoCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element chat = mensaje.getChild("addContacto");

        String uname = chat.getAttributeValue("username");
        String fav = chat.getAttributeValue("favorito");
		try {
			if(!BaseDatos.actualizaContacto(uname, fav)) return 4;
			return 0;
			
		} catch (Exception ex) {
            System.out.println(ex.getMessage());
        }
		return 0;
    }
	
	private int addItinerarioCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element add = mensaje.getChild("addItinerario");

        String id = add.getAttributeValue("id");
        String user = add.getAttributeValue("user");
		try {
			ResultSet rs = BaseDatos.consultarItinerario(id);
			if (rs.next()){
				rs.close();
				return 5;
			}
			BaseDatos.insertarItinerario(id, user);
			rs.close();
			return 0;
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        }
		return 0;
    }
	
	private int addProductoCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element add = mensaje.getChild("addProductos");

        String id = add.getAttributeValue("id");
        String precio = add.getAttributeValue("precio");
        String rating = add.getAttributeValue("rating");
        String cantidad = add.getAttributeValue("cantidad");
		try {
			ResultSet rs = BaseDatos.consultarProducto(id);
			if (rs.next()){
				rs.close();
				return 7;
			}
			BaseDatos.insertarProducto(id, precio, rating, cantidad);
			rs.close();
			return 0;
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        }
		return 0;
    }
	
	
	private int addCheckpointCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element add = mensaje.getChild("addCheckpoint");

        String fecha = add.getAttributeValue("fecha");
        String id = add.getAttributeValue("id");
        String visitado = add.getAttributeValue("visitado");
        String foto = add.getAttributeValue("foto");
        String itinerario = add.getAttributeValue("itinerario");
        String posicion = add.getAttributeValue("posicion");
		try {
			ResultSet rs = BaseDatos.consultarProducto(id);
			if (rs.next()){
				rs.close();
				return 7;
			}
			BaseDatos.insertarCheckpoint(fecha, id, visitado, foto, itinerario, posicion);
			rs.close();
			return 0;
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        }
		return 0;
    }
    
	private String getItinerarioCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element get = mensaje.getChild("getItinerario");
		String res = "";

        String user = get.getAttributeValue("user");
        System.out.println("usuario: "+user);
		try {
			ResultSet rs = BaseDatos.consultarItinerario(user);
			if (rs.next()){
				res = rs.getString("id");
				rs.close();
				return res;
			} else {
				rs.close();
				throw new Exception("Itinerario no existente");
			}
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
		} catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
		return res;
    }
	
	
	private ResultSet listarProductosCorrectos(){
		try {
			ResultSet rs = BaseDatos.listarProductos();
			if (rs.next()){
				return rs;
			} else {
				rs.close();
				throw new Exception("No hay productos!");
			}
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
		} catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
		return null;
    }
	
	private ResultSet listarCheckpointsCorrectos(Document xml){
    	Element mensaje = xml.getRootElement();
        Element listar = mensaje.getChild("listarCheckpoints");
        String itinerario = listar.getAttributeValue("itinerario");
		//ResultSet res;
		try {
			ResultSet rs = BaseDatos.listarCheckpointsPorFecha(itinerario);
			//res = rs;
			if (rs.next()){
				//rs.close();
				return rs;
			} else {
				rs.close();
				throw new Exception("No hay checkpoints para este itinerario!");
			}
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
		} catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
		return null;
    }
	
	private String getImageCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element listar = mensaje.getChild("getImage");
        String usuario = listar.getAttributeValue("user");
		String res = "";
		try {
			/*
			 * With user fetch itinerary
			 * With itinerary fetch checkpoints ordered by date
			 * Select last checkpoint that was visited
			 * Use "foto"
			 */
			ResultSet rs = BaseDatos.consultarItinerario(usuario);
			if (rs.next()){
				String iti = rs.getString("id");
				rs.close();
				rs = BaseDatos.listarCheckpointsPorFecha(iti);
				String foto = "";
				while (rs.next()){
					if (rs.getString("visitado") == "si") {
						foto = rs.getString("foto");
					} else break;
				}
				if (foto != ""){
					return StringFile.readFileAsString(usuario + File.pathSeparator + foto);
				} else return null;
			} else {
				rs.close();
				throw new Exception("No se ha encontrado el usuario, o no tiene itinerario");
			}
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
		} catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
		return res;
    }
	
	private int addImageCorrecto(Document xml){
    	Element mensaje = xml.getRootElement();
        Element add = mensaje.getChild("addImage");

        String user = add.getAttributeValue("user");
        String chk = add.getAttributeValue("checkpoint");
        String data = add.getAttributeValue("imageData");
        String foto = add.getAttributeValue("imageName");
		try {
			ResultSet rs = BaseDatos.actualizaImagenCheckpoint(chk, foto);
			if (rs.next()){
				rs.close();
				return 8;
			}
			StringFile.writeFileFromString(data, user + File.pathSeparator + foto);
			rs.close();
			return 0;
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
        } catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
		return 0;
    }
	
	private ResultSet listarContactosCorrectos(Document xml){
    	Element mensaje = xml.getRootElement();
        Element listar = mensaje.getChild("listarContactos");
        String itinerario = listar.getAttributeValue("user");
		//ResultSet res;
		try {
			ResultSet rs = BaseDatos.consultarContacto(itinerario);
			//res = rs;
			if (rs.next()){
				//rs.close();
				return rs;
			} else {
				rs.close();
				throw new Exception("No hay contactos para este usuario!");
			}
			
		} catch (SQLException ex) {
            System.out.println(ex.getMessage());
		} catch (Exception ex) {
        	System.out.println(ex.getMessage());
        }
		return null;
    }

	
}
